/*
 * Copyright 2013 Rodrigo Villablanca <villa061004@gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cl.rvillablanca.jpatch.core;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Simple implementation of {@link FileVisitor}.
 *
 * @author Rodrigo Villablanca <villa061004@gmail.com>
 * @since 1.0
 * @see FileVisitor
 */
public class Visitor extends SimpleFileVisitor<Path> {

    private static final Logger LOGGER = Logger.getLogger(Visitor.class.getName());
    private List<Path> list;
    private Path working;
    private Path base;

    /**
     * Create a new Visitor with an empty list of paths.
     *
     * @param working Path to the working sources.
     * @param base Path to the base sources.
     */
    public Visitor(Path working, Path base) {
        this.list = new ArrayList<>();
        this.working = working;
        this.base = base;
    }

    /**
     * Get list with all path of the modified files.
     *
     * @return The list with all path of the modified files.
     */
    public List<Path> getList() {
        return list;
    }

    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        LOGGER.log(Level.CONFIG, "File found: {0}", file);
        Path subPath = file.subpath(working.getNameCount(), file.getNameCount());
        LOGGER.log(Level.CONFIG, "Sub path: {0}", subPath);
        Path searchPath = Paths.get(base.toString(), subPath.toString());
        LOGGER.log(Level.CONFIG, "Search path: {0}", searchPath);
        if (Files.notExists(searchPath)) {
            LOGGER.config("File does not exists, adding to list ...");
            list.add(subPath);
        } else if (Files.exists(searchPath)) {
            LOGGER.config("File exists ...");
            try (InputStream fileIs = Files.newInputStream(file);
                    InputStream searchIs = Files.newInputStream(searchPath)) {
                boolean mustContinue = true;
                for (int a = fileIs.read(), b = searchIs.read(); mustContinue; a = fileIs.read(), b = searchIs.read()) {
                    if (a == -1 && b == -1) {
                        LOGGER.config("End reached in both files, they are the same");
                        mustContinue = false;
                    } else if (a == -1 && b != -1) {
                        LOGGER.config("End reached in working file, it is not the same, adding to list");
                        list.add(subPath);
                        mustContinue = false;
                    } else if (a != -1 && b == -1) {
                        LOGGER.config("End reached in search file, it is not the same, adding to list");
                        list.add(subPath);
                        mustContinue = false;
                    } else if (a != b) {
                        LOGGER.info("They are not the same, adding to list");
                        list.add(subPath);
                        mustContinue = false;
                    }
                }
            } catch (IOException ex) {
                LOGGER.log(Level.SEVERE, "Error ocurred while comparing paths ({0}, {1})", new Object[]{file, searchPath});
                LOGGER.log(Level.SEVERE, "Error detail: {0}", ex.getMessage());
            }
        } else {
            LOGGER.log(Level.SEVERE, "Cannot determine the file existence: {0}", searchPath);
        }
        return FileVisitResult.CONTINUE;
    }

    public void fillList() throws IOException {
        Files.walkFileTree(working, this);

    }
}
